import logging
from os import path
from json import load
from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from rest_framework import filters, generics, status
from django.core.cache import cache
from rest_framework.decorators import api_view, permission_classes
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated,IsAdminUser
from rest_framework.response import Response
from utils.filters import VulnerableDBFilter, paginate_queryset
from utils.permissions import custom_permission_required
from .models import VulnerabilityDB
from .serializers import VulnDBfetchserializers, VulnDBserializers

logger = logging.getLogger(__name__)



class Vulndbfilter(generics.ListCreateAPIView):
    permission_classes = [IsAuthenticated, IsAdminUser]
    search_fields = ['vulnerabilityname']
    filter_backends = (filters.SearchFilter,)
    serializer_class = VulnDBserializers

    def get_queryset(self):
        cache_key = 'all_vuln_data'
        queryset = cache.get(cache_key)
        if not queryset:
            queryset = VulnerabilityDB.objects.all()
            cache.set(cache_key, queryset, timeout=3600)
        return queryset

@api_view(['GET'])
@permission_classes([IsAuthenticated,IsAdminUser])
def Vulndbdata(request):
    title = request.query_params.get('title')

    cache_key = 'all_vuln_data'
    DB = cache.get(cache_key)
    if not DB:
        DB = VulnerabilityDB.objects.all()
        cache.set(cache_key, DB, timeout=3600)
    try:
        #DB = VulnerabilityDB.objects.get(vulnerabilityname=title)
        DbData = DB.filter(vulnerabilityname=title).first()
        serializer = VulnDBfetchserializers(DbData, many=False)
        return Response(serializer.data, status=status.HTTP_200_OK)
    except ObjectDoesNotExist:
        # If the vulnerability with the specified title doesn't exist
        return Response([], status=status.HTTP_200_OK)



@api_view(['GET'])
@permission_classes([IsAuthenticated,IsAdminUser])
def getallVulndbdata(request):
    #vuldbdata = VulnerabilityDB.objects.all()

    cache_key = 'all_vuln_data'
    vuldbdata = cache.get(cache_key)
    if not vuldbdata:
        vuldbdata = VulnerabilityDB.objects.all()
        cache.set(cache_key, vuldbdata, timeout=3600)

    serializer = VulnDBfetchserializers(vuldbdata,many=True)
    return Response(serializer.data)



@api_view(['GET'])
@permission_classes([IsAuthenticated,IsAdminUser])
def getallVulndbdata_filter(request):
    cache_key = 'all_vuln_data'
    vuldbdata = cache.get(cache_key)
    if not vuldbdata:
        vuldbdata = VulnerabilityDB.objects.all()
        cache.set(cache_key, vuldbdata, timeout=3600)

    vuldbdata_filter = VulnerableDBFilter(request.GET, queryset=vuldbdata)
    filtered_queryset = vuldbdata_filter.qs
    paginator, paginated_queryset = paginate_queryset(filtered_queryset, request)
    serializer = VulnDBfetchserializers(paginated_queryset, many=True)

    return paginator.get_paginated_response(serializer.data)




@api_view(['GET'])
@permission_classes([IsAuthenticated,IsAdminUser])
def getvulndb(request,pk):
    try:
        vulns = VulnerabilityDB.objects.get(pk=pk)
    except ObjectDoesNotExist:
        logger.error("Vulnerability Not Found")
        return Response({"message": "Vulnerability not found"}, status=status.HTTP_404_NOT_FOUND)

    serializer = VulnDBfetchserializers(vulns,many=False)
    return Response(serializer.data)



@api_view(['POST'])
@permission_classes([IsAuthenticated,IsAdminUser])
@custom_permission_required(['Manage Vulnerability Data'])
def add_vulndb(request):
    serializer = VulnDBfetchserializers(data=request.data)
    if serializer.is_valid(raise_exception=True):
        serializer.save()
        respdata={'Status':"Success"}
        respdata.update(serializer.data)
        return Response(respdata)
    else:
        logger.error("Serializer errors: %s", str(serializer.errors))
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['POST'])
@permission_classes([IsAuthenticated,IsAdminUser])
@custom_permission_required(['Manage Vulnerability Data'])
def edit_vulndb(request,pk):
    try:
        Vuln = VulnerabilityDB.objects.get(pk=pk)
    except ObjectDoesNotExist:
        logger.error("Vulnerability not found with pk=%s", pk)
        return Response({"message": "Vulnerability not found from VulnDB"}, status=status.HTTP_404_NOT_FOUND)

    serializer = VulnDBfetchserializers(instance=Vuln,data=request.data)
    if serializer.is_valid(raise_exception=True):
        serializer.save()
        respdata={'Status':"Success"}
        respdata.update(serializer.data)
        return Response(respdata)
    else:
        logger.error("Serializer errors: %s", str(serializer.errors))
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)



@api_view(['DELETE'])
@permission_classes([IsAuthenticated,IsAdminUser])
@custom_permission_required(['Manage Vulnerability Data'])
def delete_vulndb(request):
    Vuln = VulnerabilityDB.objects.filter(id__in=request.data)
    Vuln.delete()
    respdata={'Status':"Success"}
    return Response(respdata)



class CWEListAPIView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]
    """
    API View to list all CWEs from the JSON file.
    """

    def get(self, request, *args, **kwargs):

        cached_data = cache.get('cwe_data')
        if cached_data:
            return Response(cached_data, status=status.HTTP_200_OK)

        cwe_file_path = path.join(settings.BASE_DIR, 'data', 'cwe.json')
        
        if not path.exists(cwe_file_path):
            logger.error("CWE data file not found. Please ensure it is updated.")
            return Response(
                {"error": "CWE data file not found. Please ensure it is updated."},
                status=status.HTTP_404_NOT_FOUND
            )
        
        try:
            with open(cwe_file_path, 'r') as file:
                cwe_data = load(file)
        except Exception as e:
            logger.error("Something Went Wrong While Reading the CWE file: %s", {str(e)})
            return Response(
                {"error": f"Something Went Wrong"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        cache.set('cwe_data', cwe_data, timeout=60 * 60 * 24 * 30)
        return Response(cwe_data, status=status.HTTP_200_OK)